//
// Created by 田杰 on 2018/5/20.
//

#include "LexAn.h"


std::list<Token> &LexAn::totalLogic() {
    enum state {
        START, INID, INNUM, DONE, INAS, INASSIGN, INRA, INRANGE, INCHAR, DURCHAR, OVCHAR, OTHER, DEND
    };

    state sta = START;
    bool goOn = true;
    std::string stri;
    bool isError = false;
    bool conRead = true;

    for (Char &rec = fileRW->getNextChar(); goOn;) {
        switch (sta) {
            case START:
                stri += rec.lex;
                switch (rec.charType) {
                    case LETTER:
                        sta = INID;
                        break;
                    case NUMBER:
                        sta = INNUM;
                        break;
                    case CTEQ:
                        sta = DONE;
                        break;
                    case CTLT:
                        sta = DONE;
                        break;
                    case CTPLUS:
                        sta = DONE;
                        break;
                    case CTMINUS:
                        sta = DONE;
                        break;
                    case CTTIMES:
                        sta = DONE;
                        break;
                    case CTOVER:
                        sta = DONE;
                        break;
                    case CTLPAREN:
                        sta = DONE;
                        break;
                    case CTRPAREN:
                        sta = DONE;
                        break;
                    case CTSEMI:
                        sta = DONE;
                        break;
                    case CTLMIDPAREN:
                        sta = DONE;
                        break;
                    case CTRMIDPAREN:
                        sta = DONE;
                        break;
                    case CTENDOFILE:
                        goOn = false;
                        sta = DONE;
                        break;
                    case CTCOMMA:
                        sta = DONE;
                        break;
                    case CTCOLON:
                        sta = INAS;
                        break;
                    case CTDOT:
                        sta = INRA;
                        break;
                    case CTQUOTE:
                        sta = INCHAR;
                        break;
                    case OTHERS:
                        stri.clear();
                        conRead = false;
                        sta = OTHER;
                        break;
                }
                break;
            case INID:
                if ((rec.charType == LETTER) || (rec.charType == NUMBER))
                    stri += rec.lex;
                else {
                    sta = DEND;
                    conRead = false;
                }
                break;
            case INNUM:
                if (rec.charType == NUMBER)
                    stri += rec.lex;
                else {
                    sta = DEND;
                    conRead = false;
                }
                break;
            case DONE:
                sta = DEND;
                conRead = false;
                break;
            case INAS:
                if (rec.charType == CTEQ) {
                    stri += rec.lex;
                    sta = INASSIGN;
                } else {
                    sta = DEND;
                    conRead = false;
                }
                break;
            case INASSIGN:
                sta = DEND;
                conRead = false;
                break;
            case INRA:
                if (rec.charType == CTDOT) {
                    stri += rec.lex;
                    sta = INRANGE;
                } else {
                    sta = DEND;
                    conRead = false;
                }
                break;
            case INRANGE:
                sta = DEND;
                conRead = false;
                break;
            case INCHAR:
                if ((rec.charType == LETTER) || (rec.charType == NUMBER)) {
                    stri += rec.lex;
                    sta = DURCHAR;
                } else {
                    sta = DEND;
                    conRead = false;
                }
                break;
            case DURCHAR:
                if (rec.charType == CTQUOTE) {
                    stri += rec.lex;
                    sta = OVCHAR;
                } else {
                    sta = DEND;
                    conRead = false;
                }
                break;
            case OVCHAR:
                sta = DEND;
                conRead = false;
                break;
            case OTHER:
                if (rec.lex == ' ') {
                    conRead = true;
                    sta = START;
                    stri.clear();
                }
                else {
                    if (rec.lex == '\n') {
                        conRead = true;
                        sta = START;
                        stri.clear();
                    }
                    else {
                        isError = true;
                        stri += rec.lex;
                        sta = DEND;
                        conRead = true;
                    }
                }
                break;
            case DEND:
                if (isError) {
                    Token tok(rec.lineNumber, stri, ERROR);
                    isError = false;
                    tokList.push_back(Token(tok));
                } else {
                    Token tok(rec.lineNumber, stri);
                    fileRW->setWordType(tok);
                    tokList.push_back(Token(tok));
                }
                fileRW->ungetNextChar();
                stri.clear();
                conRead = true;
                sta = START;
                break;
        }
        if (conRead)
            rec = fileRW->getNextChar();
    }

    fileRW->writeFile(tokList);

    return tokList;
}
